package com.onpositive.datacollection.editor;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;

import com.caucho.hessian.client.HessianProxyFactory;
import com.caucho.hessian.io.AbstractDeserializer;
import com.caucho.hessian.io.AbstractHessianInput;
import com.caucho.hessian.io.AbstractHessianOutput;
import com.caucho.hessian.io.AbstractSerializer;
import com.caucho.hessian.io.AbstractSerializerFactory;
import com.caucho.hessian.io.Deserializer;
import com.caucho.hessian.io.HessianProtocolException;
import com.caucho.hessian.io.Serializer;
import com.caucho.hessian.io.SerializerFactory;
import com.onpositive.data.IReadableObjectCollection;
import com.onpositive.data.diskstorage.AbstractObjectCollection;
import com.onpositive.data.kvstorage.DataCollectionInfo;
import com.onpositive.data.kvstorage.IKeyValueCollectionCreator;
import com.onpositive.data.kvstorage.IProgress;
import com.onpositive.data.kvstorage.KeyValueCollectionCreatorFacade;
import com.onpositive.data.serializer.readers.ObjectCollectionReader;
import com.onpositive.data.serializer.readers.RandomAccessFileAccess;
import com.onpositive.datamap.core.impl.DataCollection;
import com.onpositive.semantic.model.api.command.ICommand;
import com.onpositive.semantic.model.api.command.SimpleOneArgCommand;
import com.onpositive.semantic.model.api.expressions.IListenableExpression;
import com.onpositive.semantic.model.binding.BindingStack;
import com.onpositive.semantic.model.binding.IBinding;
import com.onpositive.semantic.model.remote.HessianTransport;
import com.onpositive.semantic.model.remote.ILocalTransport;

public class CollectionsTransport extends HessianTransport implements
		ILocalTransport {

	public static class ThrowableSerializer extends AbstractSerializer {
	    @Override
	    public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
	        if (obj != null) {
	            final Class cl = obj.getClass();
	            if (out.addRef(obj))
	                return;
	            int ref = out.writeObjectBegin(cl.getName());
	            Throwable tr = (Throwable) obj;
	            ByteArrayOutputStream bos = new ByteArrayOutputStream();
	            ObjectOutputStream oos = new ObjectOutputStream(bos);
	            try {
	                oos.writeObject(tr);

	                if (ref < -1) {
	                    out.writeString("value");
	                    out.writeBytes(bos.toByteArray());
	                    out.writeMapEnd();
	                } else {
	                    if (ref == -1) {
	                        out.writeInt(1);
	                        out.writeString("value");
	                        out.writeObjectBegin(cl.getName());
	                    }
	                    out.writeBytes(bos.toByteArray());
	                }
	            } finally {
	                oos.close();
	                bos.close();
	            }
	        } else
	            out.writeNull();
	    }
	}
	public static class ThrowableDeserializer extends AbstractDeserializer {

	    @Override
	    public Class getType() {
	        return Throwable.class;
	    }

	    @Override
	    public Object readMap(AbstractHessianInput in) throws IOException {
	        int ref = in.addRef(null);
	        byte[] initValue = null;
	        while (!in.isEnd()) {
	            String key = in.readString();

	            if (key.equals("value"))
	                initValue = in.readBytes();
	            else
	                in.readString();
	        }

	        in.readMapEnd();
	        ByteArrayInputStream bis = new ByteArrayInputStream(initValue);
	        ObjectInputStream ois = new ObjectInputStream(bis);
	        try {
	            Object value = ois.readObject();
	            in.setRef(ref, value);
	            return value;
	        } catch (ClassNotFoundException e) {
	            throw new RuntimeException(e);
	        } finally {
	            ois.close();
	            bis.close();
	        }
	    }

	    @Override
	    public Object readObject(AbstractHessianInput in, Object[] fieldNames)
	            throws IOException {
	        int ref = in.addRef(null);
	        byte[] initValue = null;
	        for (Object o : fieldNames) {
	            if (o instanceof String) {
	                final String key = (String) o;
	                if (key.equals("value"))
	                    initValue = in.readBytes();
	                else
	                    in.readObject();
	            }
	        }
	        ByteArrayInputStream bis = new ByteArrayInputStream(initValue);
	        ObjectInputStream ois = new ObjectInputStream(bis);
	        try {
	            Object value = ois.readObject();
	            in.setRef(ref, value);
	            return value;
	        } catch (ClassNotFoundException e) {
	            throw new RuntimeException(e);
	        } finally {
	            ois.close();
	            bis.close();
	        }
	    }
	}
	
	public class ThrowableSerializerFactory extends SerializerFactory {
	    @Override
	    public Serializer getSerializer(Class cl) throws HessianProtocolException {
	        if (Throwable.class.isAssignableFrom(cl)) {
	            return new ThrowableSerializer();
	        }
	        return super.getSerializer(cl);
	    }

	    @Override
	    public Deserializer getDeserializer(Class cl) throws HessianProtocolException {
	        if (Throwable.class.isAssignableFrom(cl)) {
	            return new ThrowableDeserializer();
	        }
	        return super.getDeserializer(cl);
	    }
	}
	@Override
	protected HessianProxyFactory createFactory() {
		HessianProxyFactory createFactory = super.createFactory();
		createFactory.setSerializerFactory(new ThrowableSerializerFactory());
		return createFactory;
	}
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void execute(final ICommand cmd) {
		if (cmd instanceof SimpleOneArgCommand) {
			SimpleOneArgCommand m = (SimpleOneArgCommand) cmd;
			if (m.getKind().equals(SimpleOneArgCommand.ADD)) {
				IBinding caller = BindingStack.getCaller();
				System.out.println(caller);
				final DataCollectionInfo info=(DataCollectionInfo) m.getTarget();
				IListenableExpression<Object> binding = caller.getBinding("ff");
				final File fl = new File(binding.getValue().toString());
				Job ss = new Job("Uploading collection") {
					private DataCollection getDC() {
						DataCollection tc = null;
						try {
							RandomAccessFile file = new RandomAccessFile(fl,
									"r");
							RandomAccessFileAccess randomAccessFileAccess = new RandomAccessFileAccess(
									file);
							IReadableObjectCollection<?>[] collection = new ObjectCollectionReader()
									.getCollection(randomAccessFileAccess);
							tc = new DataCollection(
									(AbstractObjectCollection) collection[0],
									"Tanks", null);
						} catch (Exception e) {
							e.printStackTrace();
						}
						return tc;
					}

					@Override
					protected IStatus run(final IProgressMonitor monitor) {
						DataCollection tc = getDC();
						HessianProxyFactory d = new HessianProxyFactory();
						try {
							
							IKeyValueCollectionCreator create = (IKeyValueCollectionCreator) d
									.create(IKeyValueCollectionCreator.class,
											getConfig().getUrl()+"/cstore/");
							KeyValueCollectionCreatorFacade.storeCollection(
									create, tc, info,new IProgress() {
										
										@Override
										public void setTotal(double j) {
											monitor.beginTask("Storing collection",(int) j);
										}
										
										@Override
										public void progress(double pr) {
											monitor.worked((int) pr);
											
										}
									});
						} catch (MalformedURLException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						//innerExecute(cmd);
						fireChanged();
						return Status.OK_STATUS;
					}
				};
				ss.setUser(true);
				ss.schedule();
				PlatformUI
						.getWorkbench()
						.getProgressService()
						.showInDialog(Display.getCurrent().getActiveShell(), ss);
				return;
			}
		}
		super.execute(cmd);
	}
	@Override
	protected String transformUrl() {
		return super.transformUrl()+"/datacollections";
	}
}
